package com.elitecrm.filter;

import cn.com.callback.apiNGSTokenDemo;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.text.Normalizer;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @projectName: ngsapitask-ms
 * @package: com.elitecrm.filter
 * @className: XSSPreventionFilter
 * @author: LiJT
 * @description: TODO
 * @date: 2024-01-11 22:08
 * @version: 1.0
 */

public class XSSPreventionFilter implements Filter {
    private static final Log log = LogFactory.getLog(XSSPreventionFilter.class);
    private FilterConfig filterConfig;

    public XSSPreventionFilter() {
    }

    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.debug("doFilter:" + chain.toString());
        String allowDomains = this.filterConfig.getInitParameter("allowDomains");
        log.debug("allowDomains:" + allowDomains);
        XSSRequestWrapper wrapper = new XSSRequestWrapper((HttpServletRequest) request, allowDomains);
        chain.doFilter(wrapper, response);
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        log.debug("init:" + filterConfig.toString());
        this.filterConfig = filterConfig;
    }

    public static void main(String[] args) throws Exception {
        String value = "<img src = 'http://www.baidu.com' onerror=alert(1)> asdf <img src=\"http://www.elitecrm.com\" >";
    }

    class XSSRequestWrapper extends HttpServletRequestWrapper {
        private String allowDomains;
        private Map<String, String[]> sanitizedQueryString;
        private String[] filterLabels = new String[]{"applet", "blink", "frameset", "iframe", "object", "base", "body", "head", "layer", "style", "basefont", "embed", "html", "link", "title", "bgsound", "frame", "ilayer", "meta", "script"};
        private String[] filterAttributes = new String[]{"dynsrc", "action", "background", "bgsound", "lowsrc", "value", "onmouse(.*?)"};
        private String[] filterKeywords = new String[]{"vbscript:", "ms-its:", "firefoxurl:", "javascript:", "mhtml:", "mocha:", "data:", "livescript:"};

        public XSSRequestWrapper(HttpServletRequest request, String allowDomains) {
            //log.debug("allowDomains:" + allowDomains);
            super(request);
            this.allowDomains = allowDomains;
        }

        public String getParameter(String name) {
            log.debug("name:" + name);
            String parameter = null;
            String[] vals = (String[]) this.getParameterMap().get(name);
            if (vals != null && vals.length > 0) {
                parameter = vals[0];
            }

            return parameter;
        }

        public String[] getParameterValues(String name) {
            return (String[]) this.getParameterMap().get(name);
        }

        public Enumeration<String> getParameterNames() {
            return Collections.enumeration(this.getParameterMap().keySet());
        }

        public Map<String, String[]> getParameterMap() {
            if (this.sanitizedQueryString == null) {
                Map<String, String[]> res = new HashMap();
                Map<String, String[]> originalQueryString = super.getParameterMap();
                log.debug("originalQueryString:" + originalQueryString.toString());
                if (originalQueryString != null) {
                    Iterator var3 = originalQueryString.keySet().iterator();

                    while (var3.hasNext()) {
                        String key = (String) var3.next();
                        log.debug("var3.hasNext() key:" + key);
                        String[] rawVals = (String[]) originalQueryString.get(key);
                        String[] snzVals = new String[rawVals.length];

                        for (int i = 0; i < rawVals.length; ++i) {
                            snzVals[i] = this.stripXSS(rawVals[i]);
                        }

                        res.put(this.stripXSS(key), snzVals);
                    }
                }
                log.debug("res:" + res.toString());

                this.sanitizedQueryString = res;
            }

            return this.sanitizedQueryString;
        }

        private String stripXSS(String value) {
            log.debug("stripXSS:" + value);
            String cleanValue = null;
            if (value != null) {
                cleanValue = Normalizer.normalize(value, Normalizer.Form.NFD);
                cleanValue = cleanValue.replaceAll("\u0000", "");
                Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", 2);
                cleanValue = scriptPattern.matcher(cleanValue).replaceAll("");
                scriptPattern = Pattern.compile("eval\\((.*?)\\)", 42);
                cleanValue = scriptPattern.matcher(cleanValue).replaceAll(" ");
                scriptPattern = Pattern.compile("expression\\((.*?)\\)", 42);
                cleanValue = scriptPattern.matcher(cleanValue).replaceAll(" ");
                scriptPattern = Pattern.compile("onload(.*?)=", 42);
                cleanValue = scriptPattern.matcher(cleanValue).replaceAll(" ");
                scriptPattern = Pattern.compile("onerror(.*?)=", 42);
                cleanValue = scriptPattern.matcher(cleanValue).replaceAll(" ");
                String[] allDomainsArr = this.filterAttributes;
                int var5 = allDomainsArr.length;

                int gc;
                String gp;
                for (gc = 0; gc < var5; ++gc) {
                    gp = allDomainsArr[gc];
                    scriptPattern = Pattern.compile(gp + "[\r\n]*=[\r\n]*(\\\"|')(.*?)(\\\"|')", 42);
                    cleanValue = scriptPattern.matcher(cleanValue).replaceAll(" ");
                }

                allDomainsArr = this.filterKeywords;
                var5 = allDomainsArr.length;

                for (gc = 0; gc < var5; ++gc) {
                    gp = allDomainsArr[gc];
                    scriptPattern = Pattern.compile(gp, 2);
                    cleanValue = scriptPattern.matcher(cleanValue).replaceAll(" ");
                }

                allDomainsArr = this.filterLabels;
                var5 = allDomainsArr.length;

                for (gc = 0; gc < var5; ++gc) {
                    gp = allDomainsArr[gc];
                    scriptPattern = Pattern.compile("<" + gp + "(.*?)>", 42);
                    cleanValue = scriptPattern.matcher(cleanValue).replaceAll(" ");
                    scriptPattern = Pattern.compile("</" + gp + ">", 2);
                    cleanValue = scriptPattern.matcher(cleanValue).replaceAll(" ");
                }

                if (this.allowDomains != null && !this.allowDomains.equals("")) {
                    allDomainsArr = this.allowDomains.toLowerCase().split(";");
                    scriptPattern = Pattern.compile("src[\r\n\\s]*=[\r\n\\s]*(\\\"|'|\\\\\")(.*?)(\\\"|'|\\\\\")", 42);
                    Matcher srcMatcher = scriptPattern.matcher(cleanValue);

                    while (true) {
                        boolean findAllowDomain;
                        do {
                            do {
                                if (!srcMatcher.find()) {
                                    return cleanValue;
                                }

                                gc = srcMatcher.groupCount();
                            } while (gc < 1);

                            gp = srcMatcher.group(2);
                            findAllowDomain = false;
                        } while (gp == null);

                        gp = gp.toLowerCase();
                        if (!gp.startsWith("http://") && !gp.startsWith("https://")) {
                            findAllowDomain = true;
                        } else {
                            String[] var9 = allDomainsArr;
                            int var10 = allDomainsArr.length;

                            for (int var11 = 0; var11 < var10; ++var11) {
                                String allowDomain = var9[var11];
                                if (gp.startsWith(allowDomain)) {
                                    findAllowDomain = true;
                                    break;
                                }
                            }
                        }

                        if (!findAllowDomain) {
                            scriptPattern = Pattern.compile("src[\r\n\\s]*=[\r\n\\s]*(\\\"|'|\\\\\")" + gp + "(\\\"|'|\\\\\")", 42);
                            cleanValue = scriptPattern.matcher(cleanValue).replaceAll("");
                        }
                    }
                }
            }

            return cleanValue;
        }
    }
}
